<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RocketMQ顺序消息实现原理深度解析</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.8;
        }
        .heading {
            font-family: 'Noto Serif SC', serif;
        }
        .dropcap::first-letter {
            font-size: 4.5rem;
            float: left;
            line-height: 0.85;
            margin-right: 0.8rem;
            margin-bottom: 0.2rem;
            font-weight: 700;
            color: #3b82f6;
        }
        .code-block {
            background-color: #2d3748;
            color: #f8fafc;
            border-radius: 0.5rem;
            overflow-x: auto;
        }
        .card-hover:hover {
            transform: translateY(-4px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .transition-all {
            transition: all 0.3s ease;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="relative bg-gradient-to-r from-blue-900 to-indigo-800 text-white py-20 md:py-32 px-4">
        <div class="max-w-6xl mx-auto relative z-10">
            <div class="text-center max-w-3xl mx-auto">
                <div class="inline-block mb-6 px-4 py-2 bg-white bg-opacity-20 rounded-full text-sm font-semibold tracking-wider">
                    <i class="fas fa-rocket mr-2"></i>分布式消息系统
                </div>
                <h1 class="heading text-4xl md:text-6xl font-bold mb-6 leading-tight">RocketMQ顺序消息实现原理</h1>
                <p class="text-xl md:text-2xl opacity-90 mb-8 max-w-2xl mx-auto">深入解析全局顺序与分区顺序的设计哲学与工程实现</p>
                <div class="flex justify-center space-x-4">
                    <a href="#global-order" class="px-6 py-3 bg-white text-blue-800 font-semibold rounded-full hover:bg-gray-100 transition-all">
                        全局顺序 <i class="fas fa-arrow-down ml-2"></i>
                    </a>
                    <a href="#partition-order" class="px-6 py-3 bg-transparent border-2 border-white text-white font-semibold rounded-full hover:bg-white hover:text-blue-800 transition-all">
                        分区顺序 <i class="fas fa-arrow-down ml-2"></i>
                    </a>
                </div>
            </div>
        </div>
        <div class="absolute inset-0 bg-black opacity-20"></div>
    </section>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-4 py-16">
        <!-- Introduction -->
        <section class="mb-24">
            <div class="dropcap text-lg md:text-xl text-gray-700 mb-8">
                在分布式消息系统中，保证消息的顺序性是一个重要且复杂的问题。RocketMQ提供了两种级别的顺序消息：全局顺序和分区顺序。这两种设计模式各自适应不同的业务场景，在性能与一致性之间做出权衡，为开发者提供了灵活的选择。
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <div class="bg-white p-8 rounded-xl shadow-lg card-hover transition-all">
                    <div class="flex items-center mb-4">
                        <div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mr-4">
                            <i class="fas fa-globe text-xl"></i>
                        </div>
                        <h3 class="heading text-xl font-bold">全局顺序消息</h3>
                    </div>
                    <p class="text-gray-600">对一个指定的Topic，所有消息按照严格的FIFO顺序进行消费。实现简单但吞吐量有限，适合对顺序有严格要求但消息量不大的场景。</p>
                </div>
                <div class="bg-white p-8 rounded-xl shadow-lg card-hover transition-all">
                    <div class="flex items-center mb-4">
                        <div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 mr-4">
                            <i class="fas fa-project-diagram text-xl"></i>
                        </div>
                        <h3 class="heading text-xl font-bold">分区顺序消息</h3>
                    </div>
                    <p class="text-gray-600">对同一分区键的消息保证顺序，不同分区可并行处理。吞吐量高且能满足大多数业务场景的顺序需求，是实际应用中的首选方案。</p>
                </div>
            </div>
        </section>

        <!-- Global Order Section -->
        <section id="global-order" class="mb-24">
            <div class="flex items-center mb-8">
                <div class="w-12 h-1 bg-blue-600 mr-4"></div>
                <h2 class="heading text-3xl font-bold">全局顺序消息实现原理</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <div class="bg-white p-8 rounded-xl shadow-md">
                    <h3 class="heading text-xl font-bold mb-4 text-blue-700">核心设计</h3>
                    <ul class="space-y-4">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-list-ol text-xs"></i>
                            </div>
                            <span><strong>单队列设计</strong>：Topic下仅有一个队列(Queue)，所有消息都进入这个唯一的队列</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-stream text-xs"></i>
                            </div>
                            <span><strong>串行处理</strong>：消息按照严格的FIFO（先进先出）顺序消费</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-lock text-xs"></i>
                            </div>
                            <span><strong>锁定机制</strong>：Broker端对队列加锁，确保同一时刻只有一个消费者可以消费该队列</span>
                        </li>
                    </ul>
                </div>
                
                <div class="code-block p-6 rounded-xl">
                    <div class="flex text-sm text-gray-400 mb-4">
                        <div class="mr-4">Java</div>
                        <div>创建全局顺序Topic示例</div>
                    </div>
                    <pre><code class="language-java text-sm">// 创建只有一个队列的Topic
admin.createTopic("TopicTest", "globalOrderTopic", 1);

// 生产消息示例
Message msg = new Message("globalOrderTopic", 
    "TagA", 
    ("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET)
);
SendResult sendResult = producer.send(msg);

// 消费消息示例 - 必须使用MessageListenerOrderly
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(
        List&lt;MessageExt&gt; msgs, 
        ConsumeOrderlyContext context
    ) {
        // 处理消息
        return ConsumeOrderlyStatus.SUCCESS;
    }
});</code></pre>
                </div>
            </div>
            
            <div class="bg-blue-50 border-l-4 border-blue-600 p-6 rounded-r-lg mb-8">
                <div class="flex">
                    <div class="flex-shrink-0 text-blue-600 mr-4">
                        <i class="fas fa-info-circle text-xl"></i>
                    </div>
                    <div>
                        <h4 class="heading font-bold text-blue-800 mb-2">性能特点</h4>
                        <p class="text-blue-700">
                            <span class="font-semibold">优势：</span>实现简单，保证严格的全局顺序<br>
                            <span class="font-semibold">局限：</span>单队列成为性能瓶颈，通常TPS不超过5000/秒<br>
                            <span class="font-semibold">适用场景：</span>金融交易流水、关键操作日志等对顺序有绝对要求的场景
                        </p>
                    </div>
                </div>
            </div>
            
            <div class="mermaid mb-8">
                graph TD
                    A[生产者] -->|发送消息| B[Broker]
                    B --> C[单队列]
                    C -->|顺序消费| D[消费者1]
                    style C fill:#3b82f6,stroke:#1d4ed8,color:white
                    style D fill:#10b981,stroke:#059669,color:white
            </div>
        </section>

        <!-- Partition Order Section -->
        <section id="partition-order" class="mb-24">
            <div class="flex items-center mb-8">
                <div class="w-12 h-1 bg-indigo-600 mr-4"></div>
                <h2 class="heading text-3xl font-bold">分区顺序消息实现原理</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <div class="bg-white p-8 rounded-xl shadow-md">
                    <h3 class="heading text-xl font-bold mb-4 text-indigo-700">核心设计</h3>
                    <ul class="space-y-4">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-layer-group text-xs"></i>
                            </div>
                            <span><strong>多队列设计</strong>：Topic下有多个队列，提高并行处理能力</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-key text-xs"></i>
                            </div>
                            <span><strong>分区策略</strong>：根据分区键(如订单ID)将消息路由到固定队列</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 mt-1">
                                <i class="fas fa-lock text-xs"></i>
                            </div>
                            <span><strong>队列锁定</strong>：每个队列单独加锁，确保同一队列仅被一个消费者消费</span>
                        </li>
                    </ul>
                </div>
                
                <div class="code-block p-6 rounded-xl">
                    <div class="flex text-sm text-gray-400 mb-4">
                        <div class="mr-4">Java</div>
                        <div>分区顺序关键源码</div>
                    </div>
                    <pre><code class="language-java text-sm">// 生产者选择队列的策略
public MessageQueue selectOneMessageQueue(
    final TopicPublishInfo tpInfo, 
    final String lastBrokerName
) {
    if (this.sendLatencyFaultEnable) {
        // 容错策略
    } else {
        // 默认策略：对分区键取模选择队列
        int index = this.sendWhichQueue.getAndIncrement();
        int pos = Math.abs(index) % tpInfo.getMessageQueueList().size();
        return tpInfo.getMessageQueueList().get(pos);
    }
}

// 消费端必须实现MessageListenerOrderly
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(
        List&lt;MessageExt&gt; msgs,
        ConsumeOrderlyContext context
    ) {
        // 处理消息 - 同一队列的消息顺序处理
        return ConsumeOrderlyStatus.SUCCESS;
    }
});</code></pre>
                </div>
            </div>
            
            <div class="bg-indigo-50 border-l-4 border-indigo-600 p-6 rounded-r-lg mb-8">
                <div class="flex">
                    <div class="flex-shrink-0 text-indigo-600 mr-4">
                        <i class="fas fa-info-circle text-xl"></i>
                    </div>
                    <div>
                        <h4 class="heading font-bold text-indigo-800 mb-2">性能特点</h4>
                        <p class="text-indigo-700">
                            <span class="font-semibold">优势：</span>多队列并行处理，吞吐量高<br>
                            <span class="font-semibold">局限：</span>只保证分区内顺序，不保证全局顺序<br>
                            <span class="font-semibold">适用场景：</span>电商订单、物流状态等需要部分顺序的业务场景
                        </p>
                    </div>
                </div>
            </div>
            
            <div class="mermaid mb-8">
                graph TD
                    P[生产者] -->|消息1:订单A| Q1[队列1]
                    P -->|消息2:订单B| Q2[队列2]
                    P -->|消息3:订单A| Q1
                    P -->|消息4:订单C| Q3[队列3]
                    
                    Q1 -->|顺序消费| C1[消费者1]
                    Q2 -->|顺序消费| C2[消费者2]
                    Q3 -->|顺序消费| C3[消费者3]
                    
                    style Q1 fill:#8b5cf6,stroke:#7c3aed,color:white
                    style Q2 fill:#8b5cf6,stroke:#7c3aed,color:white
                    style Q3 fill:#8b5cf6,stroke:#7c3aed,color:white
                    style C1 fill:#10b981,stroke:#059669,color:white
                    style C2 fill:#10b981,stroke:#059669,color:white
                    style C3 fill:#10b981,stroke:#059669,color:white
            </div>
        </section>

        <!-- Reliability Section -->
        <section class="mb-24">
            <div class="flex items-center mb-8">
                <div class="w-12 h-1 bg-purple-600 mr-4"></div>
                <h2 class="heading text-3xl font-bold">顺序消息的可靠性保证</h2>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6 mb-12">
                <div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-all">
                    <div class="text-purple-600 mb-4">
                        <i class="fas fa-database text-3xl"></i>
                    </div>
                    <h3 class="heading text-lg font-bold mb-3">消息存储</h3>
                    <ul class="text-gray-600 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>同步刷盘：消息写入磁盘后才返回成功</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>同步复制：消息同步到Slave后才返回成功</span>
                        </li>
                    </ul>
                </div>
                
                <div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-all">
                    <div class="text-purple-600 mb-4">
                        <i class="fas fa-user-lock text-3xl"></i>
                    </div>
                    <h3 class="heading text-lg font-bold mb-3">消费者锁定</h3>
                    <ul class="text-gray-600 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>基于队列锁：确保队列同一时刻只被一个消费者消费</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>重平衡保护：消费者重平衡时保持队列分配不变</span>
                        </li>
                    </ul>
                </div>
                
                <div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-all">
                    <div class="text-purple-600 mb-4">
                        <i class="fas fa-shield-alt text-3xl"></i>
                    </div>
                    <h3 class="heading text-lg font-bold mb-3">故障处理</h3>
                    <ul class="text-gray-600 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>Broker故障：从Slave读取消息</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-purple-500 mr-2 mt-1"></i>
                            <span>消费者故障：新消费者从上次位点继续消费</span>
                        </li>
                    </ul>
                </div>
            </div>
        </section>

        <!-- Use Cases Section -->
        <section class="mb-24">
            <div class="flex items-center mb-8">
                <div class="w-12 h-1 bg-green-600 mr-4"></div>
                <h2 class="heading text-3xl font-bold">实际应用场景分析</h2>
            </div>
            
            <div class="grid md:grid-cols-3 gap-8">
                <!-- Case 1 -->
                <div class="bg-white rounded-xl overflow-hidden shadow-lg hover:shadow-xl transition-all">
                    <div class="h-48 bg-gradient-to-r from-yellow-400 to-orange-500 flex items-center justify-center">
                        <i class="fas fa-shopping-cart text-white text-6xl"></i>
                    </div>
                    <div class="p-6">
                        <h3 class="heading text-xl font-bold mb-3">电商订单处理</h3>
                        <p class="text-gray-600 mb-4">订单创建、支付、发货、完成等状态变更必须按顺序处理。</p>
                        <div class="bg-green-50 p-4 rounded-lg">
                            <h4 class="font-semibold text-green-800 mb-2">解决方案：</h4>
                            <p class="text-green-700">使用分区顺序消息，以订单ID作为分区键。</p>
                        </div>
                    </div>
                </div>
                
                <!-- Case 2 -->
                <div class="bg-white rounded-xl overflow-hidden shadow-lg hover:shadow-xl transition-all">
                    <div class="h-48 bg-gradient-to-r from-blue-400 to-cyan-500 flex items-center justify-center">
                        <i class="fas fa-coins text-white text-6xl"></i>
                    </div>
                    <div class="p-6">
                        <h3 class="heading text-xl font-bold mb-3">金融交易系统</h3>
                        <p class="text-gray-600 mb-4">同一账户的存取款操作必须严格按顺序处理，避免出现负余额。</p>
                        <div class="bg-green-50 p-4 rounded-lg">
                            <h4 class="font-semibold text-green-800 mb-2">解决方案：</h4>
                            <p class="text-green-700">使用分区顺序消息，以账户ID作为分区键。</p>
                        </div>
                    </div>
                </div>
                
                <!-- Case 3 -->
                <div class="bg-white rounded-xl overflow-hidden shadow-lg hover:shadow-xl transition-all">
                    <div class="h-48 bg-gradient-to-r from-purple-400 to-pink-500 flex items-center justify-center">
                        <i class="fas fa-server text-white text-6xl"></i>
                    </div>
                    <div class="p-6">
                        <h3 class="heading text-xl font-bold mb-3">数据库分库分表同步</h3>
                        <p class="text-gray-600 mb-4">将数据库变更同步到搜索引擎或缓存系统，必须保证同一数据的变更按顺序应用。</p>
                        <div class="bg-green-50 p-4 rounded-lg">
                            <h4 class="font-semibold text-green-800 mb-2">解决方案：</h4>
                            <p class="text-green-700">使用分区顺序消息，以数据ID作为分区键。</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Comparison Table -->
        <section class="mb-24">
            <div class="flex items-center mb-8">
                <div class="w-12 h-1 bg-red-600 mr-4"></div>
                <h2 class="heading text-3xl font-bold">全局顺序与分区顺序对比</h2>
            </div>
            
            <div class="bg-white rounded-xl shadow-md overflow-hidden">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                        <tr>
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">对比项</th>
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">全局顺序</th>
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">分区顺序</th>
                        </tr>
                    </thead>
                    <tbody class="bg-white divide-y divide-gray-200">
                        <tr class="hover:bg-gray-50">
                            <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">顺序保证级别</td>
                            <td class="px-6 py-4 whitespace-nowrap text-blue-600">严格的全局顺序</td>
                            <td class="px-6 py-4 whitespace-nowrap text-indigo-600">分区内顺序保证</td>
                        </tr>
                        <tr class="hover:bg-gray-50">
                            <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">队列数量</td>
                            <td class="px-6 py-4 whitespace-nowrap">1个</td>
                            <td class="px-6 py-4 whitespace-nowrap">多个</td>
                        </tr>
                        <tr class="hover:bg-gray-50">
                            <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">吞吐量</td>
                            <td class="px-6 py-4 whitespace-nowrap">低(约5000TPS)</td>
                            <td class="px-6 py-4 whitespace-nowrap">高(可线性扩展)</td>
                        </tr>
                        <tr class="hover:bg-gray-50">
                            <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">适用场景</td>
                            <td class="px-6 py-4 whitespace-nowrap">金融交易流水、关键操作日志</td>
                            <td class="px-6 py-4 whitespace-nowrap">电商订单、物流状态、数据库同步</td>
                        </tr>
                        <tr class="hover:bg-gray-50">
                            <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-900">实现复杂度</td>
                            <td class="px-6 py-4 whitespace-nowrap">简单</td>
                            <td class="px-6 py-4 whitespace-nowrap">中等</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </section>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12 px-4">
        <div class="max-w-6xl mx-auto">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-6 md:mb-0">
                    <h3 class="text-xl font-bold text-white mb-2">技术小馆</h3>
                    <p class="text-gray-400">深入探索分布式系统核心技术</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-blue-400 hover:text-blue-300 transition-colors">
                        <i class="fas fa-external-link-alt mr-2"></i> http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
            <div class="border-t border-gray-800 mt-8 pt-8 text-center text-gray-500 text-sm">
                &copy; 2023 技术小馆. 保留所有权利.
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // 平滑滚动
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>